<template>
  <div v-if="easyFlowVisible" style="height: calc(75vh);">
    <el-row>
      <!--顶部工具菜单-->
      <el-col :span="24">
        <div class="ef-tooltar">
          <el-divider direction="vertical"></el-divider>
          <el-button
            type="text"
            icon="el-icon-delete"
            size="large"
            @click="deleteElement"
            :disabled="!this.activeElement.type"
          ></el-button>
          <el-divider direction="vertical"></el-divider>
          <el-button type="text" icon="el-icon-download" size="large" @click="downloadData"></el-button>
          <el-divider direction="vertical"></el-divider>
          <el-button type="text" icon="el-icon-plus" size="large" @click="zoomAdd"></el-button>
          <el-divider direction="vertical"></el-divider>
          <el-button type="text" icon="el-icon-minus" size="large" @click="zoomSub"></el-button>
          <el-link type="primary" :underline="false" style="color: red;margin-left:50px">注：1、每个步骤节点编辑以后，需要暂存信息。2、回退与处理策略没关系，点击回退，会直接出发回退功能。</el-link>
          <div style="float: right;margin-right: 5px">
            <el-button type="info" plain round icon="el-icon-document" @click="dataInfo" size="mini" >流程信息</el-button>
            <el-button type="info" plain round icon="el-icon-document" @click="openHelp" size="mini">帮助</el-button>
          </div>
        </div>
      </el-col>
    </el-row>
    <div style="display: flex;height: calc(100% - 80px);">
      <div style="width: 180px;border-right: 1px solid #dce3e8;">
        <node-menu @addNode="addNode" ref="nodeMenu"></node-menu>
      </div>
      <div id="efContainer" ref="efContainer" class="container" v-flowDrag>
        <template v-for="node in flowData.nodeList">
          <flow-node
            :id="node.id"
            :key="node.id"
            :node="node"
            :activeElement="activeElement"
            @changeNodeSite="changeNodeSite"
            @nodeRightMenu="nodeRightMenu"
            @clickNode="clickNode"
          ></flow-node>
        </template>
        <!-- 给画布一个默认的宽度和高度 -->
        <div style="position:absolute;top:1000px;left: 800px;">&nbsp;</div>
      </div>
      <!-- 右侧表单 -->
      <div style="width: 530px;border-left: 1px solid #dce3e8;background-color: #FBFBFB">
          <NodeEditForm ref="nodeForm" @setLineLabel="setLineLabel" @repaintEverything="repaintEverything"></NodeEditForm>
      </div>
    </div>
    <div slot="footer " class="el-dialog__footer">
      <el-button size="mini" @click="closeDialog()">取消</el-button>
      <el-button size="mini" type="primary" @click="handleSave()">保存</el-button>
      <el-button size="mini" type="primary" @click="handleInstall()">安装</el-button>
    </div>

    <!-- 流程数据详情 -->
    <flow-info v-if="flowInfoVisible" ref="flowInfo" :data="flowData"></flow-info>
    <flow-help v-if="flowHelpVisible" ref="flowHelp"></flow-help>

  </div>
</template>

<script>
import draggable from "vuedraggable";
import lodash from "lodash";
// import { jsPlumb } from 'jsplumb'
// 使用修改后的jsplumb
import "../../../../utils/jsplumb";
import { easyFlowMixin } from "../../../../mixin/flow-mixins";
import { ForceDirected } from "../../../../utils/force-directed";
import flowNode from "./design/node";//节点信息
import nodeMenu from "./design/nodeMenu";//左侧可选节点
import FlowInfo from "./design/info";//流程json数据
import FlowHelp from "./design/help";
import NodeEditForm from "./design/nodeEdit";

import FlowInfoHttp from "@/api/flow/flowInfo";
//定义变量
const {
  loadSingleById,//获取单个流程信息
  loadFlowHandlerTypeList,//获取流程处理者类型
  loadFlowReturnTypeList,//获取流程退回类型
  loadFlowHandleStrategyList,//获取流程处理策略
  loadFlowSignStrategyList,//获取会签策略
  saveFlowMapl,//编辑流程详情信息【包括流程图】
  installFlowMapl,//安装流程【包括流程图】
} = FlowInfoHttp;
export default {
  //一些基础配置移动该文件中
  mixins: [easyFlowMixin],
  components: {
    draggable,
    flowNode,
    nodeMenu,
    FlowInfo,
    NodeEditForm,
    FlowHelp
  },
  props: ["formInfo"], //父界面v-bind:editInfo一致
  data() {
    return {
      jsPlumb: null,//jsPlumb 实例
      easyFlowVisible: true,//控制画布销毁
      flowInfoVisible: false,//控制流程数据显示与隐藏
      loadEasyFlowFinish: false, //是否加载完毕标志位
      flowHelpVisible: false,
      flowData: {
        nodeList:[],
        lineList:[]
      },//数据
      flowHandlerType:[],//流程处理者类型
      flowReturnType:[],//流程退回类型
      flowHandleStrategy:[],//流程处理策略
      flowSignStrategy:[],//获取会签策略
      //激活的元素、可能是节点、可能是连线
      activeElement: {
        type: undefined,//可选值node、line
        nodeId: undefined, //节点ID
        sourceId: undefined,//连线ID
        targetId: undefined
      },
      zoom: 0.5,
    };
  },
  //指令
  directives: {
    flowDrag: {
      bind(el, binding, vnode, oldNode) {
        if (!binding) {
          return;
        }
        el.onmousedown = e => {
          if (e.button == 2) {
            // 右键不管
            return;
          }
          //  鼠标按下，计算当前原始距离可视区的高度
          let disX = e.clientX;
          let disY = e.clientY;
          el.style.cursor = "move";

          document.onmousemove = function(e) {
            // 移动时禁止默认事件
            e.preventDefault();
            const left = e.clientX - disX;
            disX = e.clientX;
            el.scrollLeft += -left;

            const top = e.clientY - disY;
            disY = e.clientY;
            el.scrollTop += -top;
          };

          document.onmouseup = function(e) {
            el.style.cursor = "auto";
            document.onmousemove = null;
            document.onmouseup = null;
          };
        };
      }
    }
  },
  mounted() {
    this.jsPlumb = jsPlumb.getInstance();
    this.$nextTick(() => {
      // 默认加载流程A的数据、在这里可以根据具体的业务返回符合流程数据格式的数据即可
      this.loadFlowInfoById()
    });
    //获取类型相关列表
    this.loadTypeList();
  },
  methods: {
    ///类型相关列表-Start//////////////////////////////////////////////////
    loadTypeList(){
      let par={};
      //获取流程处理者类型
      loadFlowHandlerTypeList(par).then((response) => {
        let data = response.data;
        if (data.Code === 1000) {
           this.flowHandlerType=this.filterList(data.Data);
        }
      });
      //流程退回类型
      loadFlowReturnTypeList(par).then((response) => {
        let data = response.data;
        if (data.Code === 1000) {
           this.flowReturnType=this.filterList(data.Data);
        }
      });
      //流程处理策略
      loadFlowHandleStrategyList(par).then((response) => {
        let data = response.data;
        if (data.Code === 1000) {
           this.flowHandleStrategy=this.filterList(data.Data);
        }
      });

      //流程处理策略
      loadFlowSignStrategyList(par).then((response) => {
        let data = response.data;
        if (data.Code === 1000) {
           this.flowSignStrategy=this.filterList(data.Data);
        }
      });
      
    },
    filterList(listInfo) {
       return listInfo.filter(function(item){
          if(item.Value.toString()!= ""){
            return item;
          }
        });
    },
    ///类型相关列表-End//////////////////////////////////////////////////
    //获取单个流程信息
    loadFlowInfoById(){
      let par={
          id:this.formInfo.id
      };
      //获取流程处理者类型
      loadSingleById(par).then((response) => {
        let data = response.data;
        if (data.Code === 1000) {
          this.dataReload(data.Data);
        }
      });
    },
    ///
    //关闭增加弹出框
    closeDialog() {
      this.$emit("callBack", null);
    },
    jsPlumbInit() {
      this.jsPlumb.ready(() => {
        //导入默认配置
        this.jsPlumb.importDefaults(this.jsplumbSetting);
        //会使整个jsPlumb立即重绘。
        this.jsPlumb.setSuspendDrawing(false, true);
        //初始化节点
        this.loadEasyFlow();

        //单点击了连接线, https://www.cnblogs.com/ysx215/p/7615677.html
        this.jsPlumb.bind("click", (conn, originalEvent) => {

          this.activeElement.type = "line";
          this.activeElement.sourceId = conn.sourceId;
          this.activeElement.targetId = conn.targetId;
          this.$refs.nodeForm.lineInit({
              from: conn.sourceId,
              to: conn.targetId,
              label: conn.getLabel(),
              condition:conn.getParameter("condition")
            });
        });
        //连线
        this.jsPlumb.bind("connection", evt => {
          let from = evt.source.id;
          let to = evt.target.id;
          if (this.loadEasyFlowFinish) {
            this.flowData.lineList.push({ from: from, to: to });
          }
        });

        //删除连线回调
        this.jsPlumb.bind("connectionDetached", evt => {
          this.deleteLine(evt.sourceId, evt.targetId);
        });

        //改变线的连接节点
        this.jsPlumb.bind("connectionMoved", evt => {
          this.changeLine(evt.originalSourceId, evt.originalTargetId);
        });

        //连线右击
        this.jsPlumb.bind("contextmenu", evt => {
          console.log("contextmenu", evt);
        });

        //连线
        this.jsPlumb.bind("beforeDrop", evt => {
          let from = evt.sourceId;
          let to = evt.targetId;
          if (from === to) {
            this.$messageTip.error("节点不支持连接自己");
            return false;
          }
          if (this.hasLine(from, to)) {
             this.$messageTip.error("该关系已存在,不允许重复创建");
            return false;
          }
          if (this.hashOppositeLine(from, to)) {
             this.$messageTip.error("不支持两个节点之间连线回环");
            return false;
          }
          this.$messageTip.success("连接成功");
          return true;
        });

        //beforeDetach
        this.jsPlumb.bind("beforeDetach", evt => {
          console.log("beforeDetach", evt);
        });
        this.jsPlumb.setContainer(this.$refs.efContainer);
      });
    },
    //加载流程图
    loadEasyFlow() {
      //初始化节点
      for (var i = 0; i < this.flowData.nodeList.length; i++) {
        let node = this.flowData.nodeList[i];
        //设置源点，可以拖出线连接其他节点
        this.jsPlumb.makeSource(
          node.id,
          lodash.merge(this.jsplumbSourceOptions, {})
        );
        //设置目标点，其他源点拖出的线可以连接该节点
        this.jsPlumb.makeTarget(node.id, this.jsplumbTargetOptions);
        if (!node.view_only) {
          this.jsPlumb.draggable(node.id, {
            containment: "parent",
            stop: function(el) {
              //拖拽节点结束后的对调
              console.log("拖拽结束: ", el);
            }
          });
        }
      }
      //初始化连线
      for (var i = 0; i < this.flowData.lineList.length; i++) {
        let line = this.flowData.lineList[i];
        var connParam = {
          source: line.from,
          target: line.to,
          label: line.label ? line.label : "",
          connector: line.connector ? line.connector : "",
          anchors: line.anchors ? line.anchors : undefined,
          paintStyle: line.paintStyle ? line.paintStyle : undefined
        };
        this.jsPlumb.connect(connParam, this.jsplumbConnectOptions);
      }
      this.$nextTick(function() {
        this.loadEasyFlowFinish = true;
      });
    },
    //设置连线条件
    setLineLabel(from,to,label,condition) {
      var conn = this.jsPlumb.getConnections({
        source: from,
        target: to
      })[0];
      if (!label || label === "") {
        conn.removeClass("flowLabel");
        conn.addClass("emptyFlowLabel");
      } else {
        conn.addClass("flowLabel");
      }
      conn.setLabel({ label: label});
      conn.setParameter("condition",condition);
      
      this.flowData.lineList.forEach(function(line) {
        if (line.from == from && line.to == to) {
          line.label = label;
          line.condition = condition;
        }
      });
    },
    // 删除激活的元素
    deleteElement() {
      if (this.activeElement.type === "node") {
        this.deleteNode(this.activeElement.nodeId);
      } else if (this.activeElement.type === "line") {
        this.$messageTip.boxWarning("确定要删除吗?")
          .then(() => {
            var conn = this.jsPlumb.getConnections({
              source: this.activeElement.sourceId,
              target: this.activeElement.targetId
            })[0];
            this.jsPlumb.deleteConnection(conn);
          })
          .catch(() => {});
      }
    },
    // 删除线
    deleteLine(from, to) {
      this.flowData.lineList = this.flowData.lineList.filter(function(line) {
        if (line.from == from && line.to == to) {
          return false;
        }
        return true;
      });
    },
    // 改变连线
    changeLine(oldFrom, oldTo) {
      this.deleteLine(oldFrom, oldTo);
    },
    // 改变节点的位置
    changeNodeSite(data) {
      for (var i = 0; i < this.flowData.nodeList.length; i++) {
        let node = this.flowData.nodeList[i];
        if (node.id === data.nodeId) {
          node.left = data.left;
          node.top = data.top;
        }
      }
    },
    /**
     * 拖拽结束后添加新的节点
     * @param evt
     * @param nodeMenu 被添加的节点对象
     * @param mousePosition 鼠标拖拽结束的坐标
     */
    addNode(evt, nodeMenu, mousePosition) {
      var screenX = evt.originalEvent.clientX,
          screenY = evt.originalEvent.clientY;
      let efContainer = this.$refs.efContainer;
      var containerRect = efContainer.getBoundingClientRect();
      var left = screenX, top = screenY;
      // 计算是否拖入到容器中
      if (
        left < containerRect.x ||
        left > containerRect.width + containerRect.x ||
        top < containerRect.y ||
        containerRect.y > containerRect.y + containerRect.height
      ) {
      
        this.$messageTip.error("请把节点拖入到画布中");
        return;
      }
      left = left - containerRect.x + efContainer.scrollLeft;
      top = top - containerRect.y + efContainer.scrollTop;
      // 居中
      left -= 85;
      top -= 16;
      var nodeId = this.getUUID();
      // 动态生成名字
      var origName = nodeMenu.name;
      var nodeName = origName;
      var index = 1;
      while (index < 10000) {
        var repeat = false;
         for (var i = 0; i < this.flowData.nodeList.length; i++) {
          let node = this.flowData.nodeList[i];
          if (node.name === nodeName) {
            nodeName = origName + index;
            repeat = true;
          }
        }
        if (repeat) {
          index++;
          continue;
        }
        break;
      }
      var node = {
        id: nodeId,
        name: nodeName,
        type: nodeMenu.flow_type,
        left: left + "px",
        top: top + "px",
        icon: nodeMenu.icon,
        view_only: nodeMenu.view_only,
        is_choosable: nodeMenu.is_choosable
      };
      /**
       * 这里可以进行业务判断、是否能够添加该节点
       */
      this.flowData.nodeList.push(node);
      this.$nextTick(function() {
        this.jsPlumb.makeSource(nodeId, this.jsplumbSourceOptions);
        this.jsPlumb.makeTarget(nodeId, this.jsplumbTargetOptions);
        this.jsPlumb.draggable(nodeId, {
          containment: "parent",
          stop: function(el) {
            //拖拽节点结束后的对调
            console.log("拖拽结束: ", el);
          }
        });
      });
    },
    /**
     * 删除节点
     * @param nodeId 被删除节点的ID
     */
    deleteNode(nodeId) {
      this.$messageTip.boxWarning("确定要删除吗?")
        .then(() => {
          /**
           * 这里需要进行业务判断，是否可以删除
           */
          this.flowData.nodeList = this.flowData.nodeList.filter(function(node) {
            if (node.id === nodeId) {
              // 伪删除，将节点隐藏，否则会导致位置错位
              // node.show = false
              return false;
            }
            return true;
          });
          this.$nextTick(function() {
            this.jsPlumb.removeAllEndpoints(nodeId);
          });
        })
        .catch(() => {});
      return true;
    },
    //点击节点，编辑节点
    clickNode(node) {
      this.activeElement.type = "node";
      this.activeElement.nodeId = node.id;
      this.$refs.nodeForm.nodeInit(
                this.flowData, 
                node.id, 
                this.flowHandlerType,//流程处理者类型
                this.flowReturnType,//流程退回类型
                this.flowHandleStrategy,//流程处理策
                this.flowSignStrategy//流程会签策略
              );
    },
    // 是否具有该线
    hasLine(from, to) {
      for (var i = 0; i < this.flowData.lineList.length; i++) {
        var line = this.flowData.lineList[i];
        if (line.from === from && line.to === to) {
          return true;
        }
      }
      return false;
    },
    // 是否含有相反的线
    hashOppositeLine(from, to) {
      return this.hasLine(to, from);
    },
    nodeRightMenu(nodeId, evt) {
      this.menu.show = true;
      this.menu.curNodeId = nodeId;
      this.menu.left = evt.x + "px";
      this.menu.top = evt.y + "px";
    },
    repaintEverything() {
      this.jsPlumb.repaint();
    },
    //流程数据信息
    dataInfo() {
      this.flowInfoVisible = true;
      this.$nextTick(function() {
        this.$refs.flowInfo.init();
      });
    },
    //加载流程图
    dataReload(data) {
      this.easyFlowVisible = false;
      this.flowData.nodeList = [];
      this.flowData.lineList = [];
      this.$nextTick(() => {
        data = lodash.cloneDeep(data);
        this.easyFlowVisible = true;
        this.flowData = data;
        this.$nextTick(() => {
          this.jsPlumb = jsPlumb.getInstance();
          this.$nextTick(() => {
            this.jsPlumbInit();
          });
        });
      });
    },
    zoomAdd() {
      if (this.zoom >= 1) {
        return;
      }
      this.zoom = this.zoom + 0.1;
      this.$refs.efContainer.style.transform = `scale(${this.zoom})`;
      this.jsPlumb.setZoom(this.zoom);
    },
    zoomSub() {
      if (this.zoom <= 0) {
        return;
      }
      this.zoom = this.zoom - 0.1;
      this.$refs.efContainer.style.transform = `scale(${this.zoom})`;
      this.jsPlumb.setZoom(this.zoom);
    },
    //下载数据
    downloadData() {
      this.$messageTip.boxWarning("确定要删除吗?")
        .then(() => {
          var datastr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(this.flowData, null, "\t"));
          var downloadAnchorNode = document.createElement("a");
          downloadAnchorNode.setAttribute("href", datastr);
          downloadAnchorNode.setAttribute("download", "data.json");
          downloadAnchorNode.click();
          downloadAnchorNode.remove();
          this.$messageTip.success("正在下载中,请稍后...");
        })
        .catch(() => {});
    },
    openHelp() {
      this.flowHelpVisible = true;
      this.$nextTick(function() {
        this.$refs.flowHelp.init();
      });
    },
    //返回唯一标识
    getUUID() {
      let reg=new RegExp('-','g')//g代表全部
      return this.$uuid.v1().replace(reg,'').toUpperCase();
    },
    ////////////////////////////////////保存操作
    //保存[只操作流程主表，其他信息放在流程表的json中]
    handleSave(){
      let par=this.flowData;
      //获取流程处理者类型
      saveFlowMapl(par).then((response) => {
        let data = response.data;
            if (data.Code === 1000) {
              this.$messageTip.success(data.Msg); 
              this.$emit("callBack", data);
            } else {
              this.$messageTip.warning(data.Msg); 
            }
      });
    },
    //安装以后，会将步骤表、连线表全部给覆盖掉。
    handleInstall(){
      let par=this.flowData;
      //获取流程处理者类型
      installFlowMapl(par).then((response) => {
        let data = response.data;
        if (data.Code === 1000) {
              this.$messageTip.success(data.Msg);  
              this.$emit("callBack", data);
            } else {
              this.$messageTip.warning(data.Msg); 
            }
      });
    },
  }
};
</script>
